﻿using Ganjine;
using Ganjine.Common;
using Ganjine.DataModel;
using Ganjine_Windows10.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Popups;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Ganjine_Windows10
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class Search : Page
    {
        DataBridgeSearch Query;
        private ObservableDictionary defaultViewModel = new ObservableDictionary();
        List<PoetItem> poetsList = new List<PoetItem>();
        private bool CancelSearch = false;
        private bool isSearching = false;
        DispatcherTimer scrollSaveTimer = new DispatcherTimer();

        public Search()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Gets the DefaultViewModel. This can be changed to a strongly typed view model.
        /// </summary>
        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }


        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            Query = Newtonsoft.Json.JsonConvert.DeserializeObject<DataBridgeSearch>(e.Parameter.ToString());

            // Communicate results through the view model
            this.DefaultViewModel["SearchTerm"] = Query.term;


            //Read list of poets.
            poetsList.Add(new PoetItem() { PoetID = -1, PoetName = "همه‌ی آثار" });


            var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;

            if (localSettings.Values["poetOrders"] != null) //Default order
            {
                Dictionary<int, int> orders = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<int, int>>(localSettings.Values["poetOrders"].ToString());
                ObservableCollection<PoetItem> pc = App.dataSource.GetListOfPoets();
                foreach (var item in pc)
                {
                    item.OrderID = orders[item.PoetID];
                }

                pc = new ObservableCollection<PoetItem>(pc.OrderBy(a => a.OrderID));
                poetsList.AddRange(pc);
            }
            else
            {
                poetsList.AddRange(App.dataSource.GetListOfPoets());
            }
            this.defaultViewModel["Poets"] = poetsList;

            if (e.NavigationMode == NavigationMode.Back)
            {
                foreach (PoemItem item in App.SearchPageState.items)
                {
                    resultsListView.Items.Add(item);
                }
            }


            base.OnNavigatedTo(e);
        }

        private void MenuToggle_Click(object sender, RoutedEventArgs e)
        {
            MainView.IsPaneOpen = !MainView.IsPaneOpen;
        }

        private void BackToggle_Click(object sender, RoutedEventArgs e)
        {
            Frame.GoBack();
        }

        private async Task SearchInsideAPoet(string s, int i)
        {

            List<PoemItem> pi = new List<PoemItem>();
            //Stopwatch ss = new Stopwatch();

            await Windows.System.Threading.ThreadPool.RunAsync(_ =>
            {
                //ss.Start();    
                //pi.AddRange((List<PoemItem>)this.defaultViewModel["SearchResults"]);
                pi.AddRange(App.dataSource.Search(s, i));


                //ss.Stop();
            }, Windows.System.Threading.WorkItemPriority.Low, Windows.System.Threading.WorkItemOptions.None);
            /*var dialog = new MessageDialog("with await: " + ss.ElapsedMilliseconds.ToString() + "ms");
            await dialog.ShowAsync();*/


            foreach (PoemItem item in pi)
            {
                if (!App.SearchPageState.stringItems.Contains(item.Text))
                {
                    resultsListView.Items.Add(item);
                    App.SearchPageState.items.Add(item);
                    App.SearchPageState.stringItems.Add(item.Text);
                }
            }
        }

        private async Task DoSearch(string queryText)
        {
            isSearching = true;
            App.SearchQuery = queryText;

            CancelSearch = false;
            NoResults.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
            string s = queryText;
            int i;
            try { i = ((PoetItem)searchSource.SelectedItem).PoetID; }
            catch { i = -1; }
            App.SearchQuery = s;

            if (App.SearchPageState.items.Count == 0)
                resultsListView.Items.Clear();

            if (i > 0)
            {
                searchProgressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                searchProgressBar2.Visibility = Windows.UI.Xaml.Visibility.Visible;
                await SearchInsideAPoet(s, i);
                searchProgressBar2.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
            }
            else
            {
                int firstNewPoet = App.SearchPageState.firstNewPoet;

                searchProgressBar2.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                searchProgressBar.Visibility = Windows.UI.Xaml.Visibility.Visible;
                searchProgressBar.Minimum = 0;
                searchProgressBar.Value = firstNewPoet;
                searchProgressBar.Maximum = poetsList.Count;

                for (int x = firstNewPoet; x < poetsList.Count; x++)
                {
                    if (App.SearchPageState.stringItems.Count > App._maxSearchResultsCount)
                    {
                        PoemItem lastItem = new PoemItem();
                        lastItem.ID = -10;
                        lastItem.Text = "*** تعداد نتایج خیلی زیاد است ***";
                        lastItem.s1 = "برای دیدن نتایج بیشتر، لطفاً جست‌و‌جو را به یک شاعر محدود نمایید.";
                        resultsListView.Items.Add(lastItem);
                        
                        CancelSearch = true;
                        break;
                    }

                    App.SearchPageState.firstNewPoet = x;
                    PoetItem pi = ((PoetItem)poetsList[x]);
                    await SearchInsideAPoet(s, pi.PoetID);

                    if (CancelSearch)
                    {
                        break;
                    }
                    searchProgressBar.Value = x + 1;
                }
                searchProgressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
            }



            if ((resultsListView.Items.Count == 0) && (!CancelSearch))
            {
                NoResults.Visibility = Windows.UI.Xaml.Visibility.Visible;
            }

            isSearching = false;
        }

        private async void searchSource_ItemClick(object sender, ItemClickEventArgs e)
        {
            searchSource.SelectedItem = e.ClickedItem;
            CancelSearch = true;

            App.SearchPageState.Reset();
            resultsListView.Items.Clear();

            MainView.IsPaneOpen = (MenuToggle.Visibility != Visibility.Visible);
            searchProgressBar2.Visibility = Visibility.Visible;
            searchProgressBar.Value = 0;

            //wait until currentSearch finishes.
            while (isSearching)
            {
                await Task.Delay(TimeSpan.FromMilliseconds(100));
            }


            /* Clear again, there might be some new items added now */
            App.SearchPageState.Reset();
            resultsListView.Items.Clear();

            App.SearchPageState.PoetIndex = searchSource.SelectedIndex;

            await DoSearch(Query.term);
        }

        private void resultsListView_ItemClick(object sender, ItemClickEventArgs e)
        {
            PoemItem pi = (PoemItem)e.ClickedItem;

            if (pi.ID < 0)
                return;

            DataBridge2 db = new DataBridge2()
            {
                parentid = 0,
                id = pi.ID,
                title = pi.Text,
                HideNextPrevKeys = true
            };
            Frame.Navigate(typeof(ItemPage), Newtonsoft.Json.JsonConvert.SerializeObject(db));

            /*App.mainDispatcher = Dispatcher;

            var currentAV = ApplicationView.GetForCurrentView();
            var newAV = CoreApplication.CreateNewView();
            await newAV.Dispatcher.RunAsync(
                            CoreDispatcherPriority.Normal,
                            async () =>
                            {
                                var newWindow = Window.Current;
                                var newAppView = ApplicationView.GetForCurrentView();
                                newAppView.Title = currentAV.Title;

                                var frame = new Frame();
                                frame.Navigate(typeof(ItemPage), Newtonsoft.Json.JsonConvert.SerializeObject(db));
                                newWindow.Content = frame;
                                newWindow.Activate();

                                await ApplicationViewSwitcher.TryShowAsStandaloneAsync(
                                    newAppView.Id,
                                    ViewSizePreference.UseMinimum,
                                    currentAV.Id,
                                    ViewSizePreference.UseMinimum);
                            });*/
        }

        private void backButton_Click(object sender, RoutedEventArgs e)
        {
            CancelSearch = true;
        }

        private async void Page_Loaded(object sender, RoutedEventArgs e)
        {
            SetSearchButtonOpacity();

            if (App.SearchPageState.PoetIndex == -1)
            {
                searchSource.SelectedIndex = 0;
                foreach (var item in poetsList)
                {
                    if (Query.sourceId == item.PoetID)
                    {
                        searchSource.SelectedItem = item;
                    }
                }
            }
            else
                searchSource.SelectedIndex = App.SearchPageState.PoetIndex;

            searchSource.ScrollIntoView(searchSource.SelectedItem);

            if (App.SearchPageState.items.Count > 0)
            {
                var scrollViewer = VisualChildFinder.FindVisualChild<ScrollViewer>(resultsListView);
                scrollViewer.ChangeView(scrollViewer.HorizontalOffset, App.SearchPageState.scrollPosition, scrollViewer.ZoomFactor, true);
            }

            scrollSaveTimer.Interval = TimeSpan.FromSeconds(0.2);
            scrollSaveTimer.Tick += ScrollSaveTimer_Tick;
            scrollSaveTimer.Start();

            await DoSearch(Query.term);
        }

        private void ScrollSaveTimer_Tick(object sender, object e)
        {
            var scrollViewer = VisualChildFinder.FindVisualChild<ScrollViewer>(resultsListView);
            if (scrollViewer != null)
            {
                App.SearchPageState.scrollPosition = scrollViewer.VerticalOffset;
                Debug.WriteLine(scrollViewer.VerticalOffset);
            }
        }

        protected async override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            scrollSaveTimer.Stop();

            scrollSaveTimer.Tick -= ScrollSaveTimer_Tick;
            Window.Current.CoreWindow.CharacterReceived -= KeyPress;


            CancelSearch = true;
            while (isSearching)
            {
                await Task.Delay(TimeSpan.FromMilliseconds(100));
            }

            if (e.NavigationMode == NavigationMode.Back)
            {
                App.SearchPageState.Reset();
            }

            base.OnNavigatingFrom(e);
        }

        private async void SearchButton_Click(object sender, RoutedEventArgs e)
        {
            if (SearchTextBox.Text.Length < App._minSearchTextLength)
                return;

            App.SearchPageState.Reset();

            CancelSearch = true;
            searchProgressBar2.Visibility = Visibility.Visible;
            searchProgressBar.Value = 0;
            while (isSearching)
            {
                await Task.Delay(TimeSpan.FromMilliseconds(100));
            }

            Query.term = SearchTextBox.Text;

            await DoSearch(Query.term);
        }


        private void SearchTextBox_KeyUp(object sender, KeyRoutedEventArgs e)
        {
            if (e.Key == Windows.System.VirtualKey.Enter)
            {
                SearchButton_Click(sender, new RoutedEventArgs());
            }
        }


        private void KeyPress(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.CharacterReceivedEventArgs args)
        {
            if (FocusManager.GetFocusedElement() is TextBox)
                return;

            if ((SearchTextBox.FocusState == Windows.UI.Xaml.FocusState.Unfocused) &&
                (SearchBar.Visibility == Visibility.Visible))
            {
                Char c = Convert.ToChar(args.KeyCode);
                if (Char.IsLetterOrDigit(c))
                {
                    SearchTextBox.Text = c.ToString();
                    SearchTextBox.SelectionStart = SearchTextBox.Text.Length;
                    SearchTextBox.SelectionLength = 0;
                    SearchTextBox.Focus(FocusState.Programmatic);
                }
            }
        }

        private void KeyPressEventRegister()
        {
            if (SearchBar.Visibility == Visibility.Visible)
                Window.Current.CoreWindow.CharacterReceived += KeyPress;
            else
                Window.Current.CoreWindow.CharacterReceived -= KeyPress;
        }
        

        private void pageRoot_GotFocus(object sender, RoutedEventArgs e)
        {
            KeyPressEventRegister();
        }

        private void pageRoot_LostFocus(object sender, RoutedEventArgs e)
        {
            //Window.Current.CoreWindow.CharacterReceived -= KeyPress;
            //System.Diagnostics.Debug.WriteLine("LostFocus");
        }

        private void Page_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            KeyPressEventRegister();
        }

        private void SetSearchButtonOpacity()
        {
            SearchButton.Opacity = (SearchTextBox.Text.Length >= App._minSearchTextLength) ? 1 : 0.3;
        }

        private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            SetSearchButtonOpacity();
        }
    }
}
